I am working on an interactive widget and merging changes provided by a user over it with the app. I store my data, using Core Data. However, I noticed an issue with sync between other user's devices after that person made a change over the widget (in my case, it is completing a task). Here is my schema:
Main app: it looks for relevant transactions (https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes). When it found that one, the app merges changes:
if transaction.author == "widget" {
if let userInfo = transaction.objectIDNotification().userInfo {
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: userInfo, into: [taskContext])
}
}
Widget: If the user clicks on the checkbox in order to complete a task, using an AppIntent class, app creates an identical NSPersistentCloudKitContainer and completes the task. However, in that case, the NSPersistentCloudKitContainer of the widget does not look for changes.
That works correctly. However, only in a local environment. Here's why:
If I complete a task (using a widget) and launch the app on the same device, the change will be synced correctly.
If I complete a task (using a widget) (on device A) and launch the app on another device (on device B), the change will not be applied (on device B), until I open the app on the device that I made the change on (on device A).
If I open the app on device B after I opened it on device A (and the changed has been applied), on device A I get a remote notification with the author value = 'NSCloudKitMirroringDelegate.import', not 'widget'.
The point of my issue is that the remote notifications about changes made, using widgets, does not arrive to other devices like notifications initialised by the main app. Thank you in advance!
Post
Replies
Boosts
Views
Activity
Hello,
I am working with sharing over Core Data. I would like to implement my own UI to share records and manage participants. In the CKShare's documentation we can read:
However, only the owner can delete a shared hierarchy’s root record. If a participant attempts to delete the share, CloudKit removes the participant. The share remains active for all other participants (https://developer.apple.com/documentation/cloudkit/ckshare).
However, when I delete a shared NSManagedObject (as a participant), using self.moc.delete(sharedProject), the object is deleted even for its owner.
On the other hand, accoring to the "Sharing Core Data objects between iCloud users" documentation (https://developer.apple.com/documentation/coredata/sharing_core_data_objects_between_icloud_users), to delete a share, we should use the purgeObjectsAndRecordsInZone(with:in:completion:) method. And that works, however, NSManagedObjectContext doesn't merge changes. Moreover, in the same documentation we can read:
Manages the participants of the share from the owner side using addParticipant(:) and removeParticipant(:), or stops the sharing by calling purgeObjectsAndRecordsInZone(with:in:completion:).
Unfortunately, calling that method from the owner side leads to deletion of the shared record.
Do you have any ideas how to receive a similar effect like in the UICloudSharingController?
I am working with sharing data through CloudKit and Core Data. I share NSManagedObjects, using:
persistentContainer.share([object], to: nil) { sharedIDs, s, container, error in
if let error = error {
fatalError(error.localizedDescription)
}
if let share = s {
completion(share)
}
}
and that works. However, when I would like to receive the CKShare's object, using:
let operation = CKFetchShareMetadataOperation(shareURLs: [shareURL])
operation.shouldFetchRootRecord = true
var cache = [CKShare.Metadata]()
operation.perShareMetadataResultBlock = { url, result in
switch result {
case .failure(let error):
print("\(#function) Error during downloading the metadata for \(url.absoluteString): ", error.localizedDescription)
case .success(let metadata):
cache.append(metadata)
}
}
operation.fetchShareMetadataResultBlock = { result in
switch result {
case .failure(let error):
completion(.failure(error))
case .success(_):
completion(.success(cache))
}
}
operation.qualityOfService = .userInitiated
CKContainer.default().add(operation)
The metadata's rootRecord is always nil. In the Apple's documentation we can read:
For a shared record hierarchy, the hierarchicalRootRecordID property contains the ID of the share’s root record. When using CKFetchShareMetadataOperation to fetch metadata, you can include the entire root record by setting the operation’s shouldFetchRootRecord property to true (...). This functionality isn’t applicable for a shared record zone because, unlike a shared record hierarchy, it doesn’t have a nominated root record (https://developer.apple.com/documentation/cloudkit/ckshare/metadata).
Is there a different way to get the shared object from CKShare?
I am working with the CKDiscoverAllUserIdentitiesOperation. I would like to fetch all users, however, CloudKit returns the following error:
<CKError 0x6000009ce040: "Request Rate Limited" (7/2058); "Operation throttled by previous server http 429 reply. Retry after 6432.8 seconds. (Other operations may be allowed.)"; Retry after 6432.8 seconds>
Here's my code:
var identities = [CKUserIdentity]()
let operation = CKDiscoverAllUserIdentitiesOperation()
operation.userIdentityDiscoveredBlock = { userIdentity in
identities.append(userIdentity)
}
operation.discoverAllUserIdentitiesCompletionBlock = { error in
if let error = error {
fatalError(error.localizedDescription)
} else {
completion(identities)
}
}
operation.qualityOfService = .userInitiated
CKContainer.default().add(operation)
App adds that operation in the viewDidAppear method . Also I have requested to the application permission for user discoverability (accodring to the Apple's documentation: https://developer.apple.com/documentation/cloudkit/ckdiscoveralluseridentitiesoperato)
Hi! I'm working with a drag and drop method, using a collection view. Is there possible to return UICollectionViewDropProposal (in the collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal method) with both intents: .insertAtDestinationIndexPath and .insertIntoDestinationIndexPath? I would like to recive a feature like on iOS Reminders - you may insert into list (and create a group) or insert at (and reorder). Thanks in advance.
Hi.
I work with a UICollectionViewController (as a primary view of UISplitViewController), compile my app on the iPad and the iPhone. The collection view behaves normally on the iPhone but on the iPad I noticed somtheing strange: 1. the selected cell has a border (strokeWidth is equal to 0 in and customView is equal to nil in UIBackgroundConfiguration); 2. Visible cells are too wide (look at the attachment)
During dragging
Any ideas how to repair? Thanks in advance.
Hello! I'm working with the UIHostingConfiguration and would like to set a Toolbar for a TextField which I placed in the content. I've tried to set ToolbarRole and Toolbar Visibility. Unfortunately, it doesn't work. Here's my example code:
Cell:
cell.configurationUpdateHandler = { (cell, state) in
cell.contentConfiguration = UIHostingConfiguration {
RowView(item: item)
}
}
View:
@ObservedObject var item: Movie
var body: some View {
TextField("Title", text: $item.title)
.toolbar(content: {
ToolbarItem(placement: .keyboard) {
Button("Confirm", action: {})
}
})
.toolbar(.visible, in: .automatic)
}
}
Hi! I'm experimenting with UIHostingConfiguration. I put a textfield in the cell's coniguration and would like to observe its state. I created a @FocusState variable and set the focused(_:). But I've noticed that @FocusState doesn't work in UIHostingConfiguration. Here' my code:
struct TaskView: View {
@ObservedObject var task: Task
@FocusState private var isFocused: Bool
var body: some View {
HStack(spacing: 10) {
Image(systemName: (task.isCompleted == true) ? "checkmark.square.fill" : "square")
.font(Font.system(size: 20, weight: .medium))
.foregroundColor(.gray)
.onTapGesture {
task.isCompleted = true
}
VStack(alignment: .leading, spacing: 3) {
TextField("Task", text: $task.name)
.onSubmit {
try! (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext.save()
}
.focused($isFocused)
.submitLabel(.done)
.onChange(of: isFocused) { newValue in
print(newValue) //always returns false
}
HStack(spacing: 2) {
Image(systemName: "moon.fill")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.blue)
Text("Tomorrow")
.font(.footnote).bold()
.foregroundColor(.gray)
}
}
}
}
}
Can I use NSManagedObject with @ObservableObject and @Published to auto-reconfigure my collection view's cells?
Currently, I work with CKSubcription and remote notifications. I have a question concerns application(_:didReceiveRemoteNotification:fetchCompletionHandler:) method. In Apple's documentations we can read:
As soon as you finish processing the notification, you must call the block in the handler parameter or your app will be terminated. Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block. In practice, you should call the handler block as soon as you are done processing the notification.
Source: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application
The method works correctly. My app "wakes up" when got a notification (to observe that, I use option + command + escape). Do I correctly undrestand? - when I call hadler block, should app close immediately? My app closes after 30 second, even if I put only completionHandler(...) in this method. I asked beacuse in the documentation we can read.
Your app has UP to 30 seconds
Thank you in advance.
I work with Core Data and I needed to change CloudKit container in Singing & Capabilities. I've done it successed, I think. But when I run my app, NSCloudKitMirroringDelegate returns the error with user info:
NSLocalizedFailureReason=Subscription save succeeded but did not return 'com.apple.coredata.cloudkit.shared.subscription' as a saved subscription
I've registred my app's ID and I've checked iCloud. Thanks in advanced.
I'm trying to use NSFetchedResultsController with UICollectionView List. It works good, but when NSFetchedResultsController detect changes I get error:
Could not cast value of type '_NSCoreDataTaggedObjectID' (0x7fff8091b280) to 'ProjectName.Person' (0x1053479e0).
It's my code:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
if dataSource==nil {
return
}
guard let dataSource = collectionView?.dataSource as? UICollectionViewDiffableDataSource<Int, Person> else {
return
}
var snapshot = snapshot as NSDiffableDataSourceSnapshot<Int, Person>
let currentSnapshot = dataSource.snapshot() as NSDiffableDataSourceSnapshot<Int, Person>
let reloadIdentifiers: [Person] = snapshot.itemIdentifiers.compactMap { itemIdentifier in
guard let currentIndex = currentSnapshot.indexOfItem(itemIdentifier), let index = snapshot.indexOfItem(itemIdentifier), index == currentIndex else {
return nil
}
guard let existingObject = try? controller.managedObjectContext.existingObject(with: itemIdentifier.objectID), existingObject.isUpdated else { return nil }
return itemIdentifier
}
snapshot.reloadItems(reloadIdentifiers)
let shouldAnimate = collectionView?.numberOfSections != 0
dataSource.apply(snapshot as NSDiffableDataSourceSnapshot<Int, Person>, animatingDifferences: shouldAnimate)
}
Please help
I’d like to write expanding rows in UITableView, which display content from NSFetchedResultsController. It’s struct of object: • Object • array of sub-objects I can’t insert new rows with expanded sub-objects. Please help.
I have issue. I'd like to place attachment (like on attached picture; it's Notes on iOS) in UITextView. I tried use NSTextAttachment, but on iOS I couldn't use NSTextAttachmentCell. I'd like to attachment will be part of text. I've tried use exclusion paths, but custom view wasn't be a part of text.
Thank you.
Hi!
I have question. How can I insert image to text view with smaller size(scaled to text view), but with keeping quality? Like in Notes on iOS - picture with high quality weight around 800kB. Thanks.